#pragma once

#ifndef _CR_CORE_SINGLETON_H_
#define _CR_CORE_SINGLETON_H_

NS_CR_BEGIN

class CR_DLL singleton_module
{
private:
	static bool& get_lock()
	{
		static bool lock = false;
		return lock;
	}
// 
// 	singleton_module(const singleton_module&)
// 	{}
// 	const singleton_module& operator=(const singleton_module&)
// 	{
// 		return *this;
// 	}
public:
	singleton_module() = default;
	static void lock()
	{
		get_lock() = true;
	}

	static void unlock()
	{
		get_lock() = false;
	}

	static bool is_locked()
	{
		return get_lock();
	}
};

namespace detail
{
	template<typename T>
	class singleton_wrapper : public T
	{
	public:
		static bool m_is_destroyed;
		~singleton_wrapper()
		{
			m_is_destroyed = true;
		}
	};

	template <typename T>
	bool detail::singleton_wrapper< T >::m_is_destroyed = false;
}

template <typename T> 
class singleton : public singleton_module
{
private:
	static T& instance;

	static void use(T const&) 
	{}

	static T& get_instance()
	{
		static detail::singleton_wrapper<T> t;
		CR_ASSERT(!detail::singleton_wrapper< T >::m_is_destroyed);
		use(instance);
		return static_cast<T &>(t);
	}

public:
	static T& get_mutable_instance()
	{
		CR_ASSERT(!is_locked());
		return get_instance();
	}

	static const T& get_const_instance()
	{
		return get_instance();
	}

	static bool is_destroyed()
	{
		return detail::singleton_wrapper< T >::m_is_destroyed;
	}
};

template <typename T>
T& singleton<T>::instance = singleton<T>::get_instance();

NS_CR_END

#endif // !_CR_CORE_SINGLETON_H_
